package sde.actor.sfa;
import java.io.*;
import java.util.*;
import sde.actor.*;

class Source extends Actor{
   //interfaccia messaggi
   public static class Init extends Message{
      double lambda;
      Station s;
      public Init( double lambda, Station s ){
         this.lambda=lambda; this.s=s;
      }
   }//Init
   public static class Generate extends Message{}
   //dati locali
   private double lambda;
   private RandomGenerator r=new RandomGenerator();
   private Station s;
    private final int CREATED=0, GENERATING=1;
   public Source(){
	   become( CREATED );
   }
   public void handler( Message m ){
	  switch( currentStatus() ){
	  case CREATED:
		  if( m instanceof Init ){
			  Init init=(Init)m;
			  s=init.s; lambda=init.lambda;
			  send( new Generate(), now()+r.exponential( lambda ) );
			  become( GENERATING );
		  } break;
	  case GENERATING:
		  if( m instanceof Generate ){
			  s.send( new Station.Arrival() );
			  send( m, now()+r.exponential( lambda ) );
		  }
	  }
   }//handler
}//Source

class Station extends Actor{
   //interfaccia messaggi
   public static class Init extends Message{
      double mu;
      Path p;
      public Init( double mu, Path p )
      { this.mu=mu; this.p=p; }
   }//Init
   public static class Arrival extends Message{}
   private static class Departure extends Message{}
   //stati interni
   private final int CREATED=0, FREE=1, BUSY=2;
   private RandomGenerator r=new RandomGenerator();
   private LinkedList<Message> WaitingLine=new LinkedList<Message>();
   private double mu;
   private Departure departure=new Departure();
   private Path p;
   Station(){ become(CREATED); }
   public void handler( Message m ){
      switch( currentStatus() ){
         case CREATED:
            if( m instanceof Init ){
               Init init=(Init)m;
               mu=init.mu; p=init.p;
               become( FREE );
            } break;
         case FREE:
            if( m instanceof Arrival ){
              send( departure, now()+r.exponential( mu ) );
              p.up( now() ); become( BUSY );
            } break;
         case BUSY:
            if( m instanceof Departure ){          	
              p.down( now() );
              if( WaitingLine.size()==0 ) become( FREE );
              else {
                 WaitingLine.removeFirst();
                 send( m, now()+r.exponential( mu ) );
              }
            }
            else if( m instanceof Arrival ){            	
               p.up( now() );
               WaitingLine.addLast( m );
            }
      }//switch
   }//handler
}//Station

public class SFA{
   public static void main(String args[]) throws java.io.IOException {
      BufferedReader br=
         new BufferedReader( new InputStreamReader(System.in) );
      double mediaInterarrivi=0.0, mediaServizi=0.0;
      double tEnd=0;
      System.out.println("Fornisci su linee separate mediaInterarrivi(1/lambda di source)"+
      " mediaServizi(1/mu di station) tEnd");
      mediaInterarrivi=Double.valueOf(br.readLine()).doubleValue();
      System.out.println("1/lambda="+mediaInterarrivi);
      mediaServizi=Double.valueOf(br.readLine()).doubleValue();
      System.out.println("1/mu="+mediaServizi);
      tEnd=Double.valueOf(br.readLine()).doubleValue();
      System.out.println("tEnd="+tEnd);
      ControlMachine cm=new Simulation( tEnd );
      Path p=new Path();
      Station station=new Station();
      station.send( new Station.Init( 1/mediaServizi, p ) );
      Source source=new Source( );
      source.send( new Source.Init( 1/mediaInterarrivi, station ) );
      cm.controller();
      System.out.println
         ("Numero medio di clienti in attesa = "+
           String.format("%1.2f%n", p.mean( tEnd )) );
   }
}//SFA

